package com.hp.bon.sgw.service;

import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.bean.BlackSumSgwViewBean;
import com.hp.bon.sgw.bean.BlacklistRuleView;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.domain.BlackListResult;
import com.hp.bon.sgw.domain.SgwViewDao;
import com.hp.bon.sgw.start.SpringContext;
import com.hp.bon.sgw.util.dcc.DccAvpHelper;

/**
 * 黑名单控制（单例）
 * 
 * @author yudan
 * 
 */
public class BlackListSgwViewService implements ConfigListener {
	private static final Logger logger = LoggerFactory.getLogger(BlackListSgwViewService.class);

	private static BlackListSgwViewService instance;
	
	/**
	 * 记录流量，key是hostId<serviceContextId>
	 */
	private ConcurrentHashMap<String, BlackSumSgwViewBean> blackSumMap = new ConcurrentHashMap<String, BlackSumSgwViewBean>();

	public static BlackListSgwViewService getInstance() {
		if (instance == null) {
			instance = new BlackListSgwViewService();
			instance.init();

			SpringContext.getInstance().getConfigService().addConfigListener(instance);
		}
		return instance;
	}

	private BlackListSgwViewService() {}
	
	/**
	 * 收到业务请求后，检查是否是黑名单
	 * 
	 * @param callParam
	 * @return
	 */
	public String checkAllowConnect(CallParam callParam) {
		String hostId = callParam.getFromNode().getHostId();
		String serviceContextId = callParam.getServiceContextId();
		
		BlacklistRuleView rule = getBlackCfg(callParam);
		if (rule == null) {
			return null;
		}
		Object request = callParam.getRequest();
		if (request == null) {
			return null;
		}
		String keyVal = DccAvpHelper.getValueByPath(request, rule.getKeyXmlTag(), rule.getKeyAvpPath());
		if (keyVal == null) {
			return null;
		}
		
		Map<String, BlackListResult> blackResultMap = SpringContext.getInstance().getConfigService().getBlackListResultMap();
		String resultKey = this.getBlackResultMapKey(hostId, serviceContextId, rule.getKeyXmlTag(), keyVal);
		BlackListResult blackResult = blackResultMap.get(resultKey);
		if (blackResult == null) {
			return null;
		} 
		return resultKey;
	}

	public void init() {
		;
	}

	public void doPeriodWork() {
		checkAndRestBlackBean();
	}

	/**
	 * 检查是否超过黑名单配置阀值,并加入黑名单
	 * @param 
	 * @return
	 */
	public void checkAddBlackList(CallParam callParam) {
		String hostId = callParam.getUserName();
		String serviceContextId = callParam.getServiceContextId();
		
		Object request = callParam.getRequest();
		if (request == null) {
			return;
		}
		BlacklistRuleView blackRule = this.getBlackCfg(callParam);
		if (blackRule == null) {
			return;
		}
		String rcXmlTag = DccAvpHelper.getValueByPath(request, blackRule.getKeyXmlTag(), null);
		if (rcXmlTag == null) {
			return;
		}
		
		if(checkAllowConnect(callParam) != null){
			return;
		}

		if(blackRule.getRcMap().contains(callParam.getServiceResultCode())){
			String sumKey = this.getBlackSumMapKey(hostId, serviceContextId, blackRule.getKeyXmlTag(), rcXmlTag);
			BlackSumSgwViewBean fluxBean = findBlackSumSgwViewBean(sumKey);
			fluxBean.increAccess();
			
			long totalReq = fluxBean.getTotalRequests();
			if (totalReq > blackRule.getBlackNum()) {
				putToBlackList(hostId, serviceContextId, blackRule, rcXmlTag);
			}
		}
		
	}
	
	//获取黑名单配置key
	private String getCfgMapKey(String hostId, String serviceContextId){
		return String.format("<%s><%s>", hostId, serviceContextId);
	}
	
	//获取黑名单列表key
	private String getBlackResultMapKey(String hostId, String serviceContextId, String keyXmlTag, String rcXmlTag){
		return String.format("<%s><%s>[%s][%s]", hostId, serviceContextId, keyXmlTag, rcXmlTag);
	}
	
	//获取黑名计数key
	private String getBlackSumMapKey(String hostId, String serviceContextId, String keyXmlTag, String rcXmlTag){
		return this.getBlackResultMapKey(hostId, serviceContextId, keyXmlTag, rcXmlTag);
	}

	//加入黑名单列表，并持久化到DB
	private void putToBlackList(String neHostID, String serviceContextId, BlacklistRuleView blackRule, String rcXmlTag) {
		String key = this.getBlackResultMapKey(neHostID, serviceContextId, blackRule.getKeyXmlTag(), rcXmlTag);
		
		BlackListResult vo = new BlackListResult();
		vo.setBlackState("00A");
		vo.setBlackTime(null);
		vo.setHostId(neHostID);
		vo.setServiceContextId(serviceContextId);
		vo.setKeyXmlTag(blackRule.getKeyXmlTag());
		vo.setRcXmlTag(rcXmlTag);
		vo.setStateDate(new Date());
		vo.setUserIp("");
		//TO DO save
		SgwViewDao dao = (SgwViewDao)SpringContext.getApplicationContext().getBean(SgwViewDao.class);
		dao.saveBlackListResult(vo);
		
		Map<String, BlackListResult> blackResultMap = SpringContext.getInstance().getConfigService().getBlackListResultMap();
		blackResultMap.put(key, vo);
		logger.info("add to sgw-view black list: " + key);
	}

	private BlackSumSgwViewBean findBlackSumSgwViewBean(String key) {
		BlackSumSgwViewBean fluxBean = blackSumMap.get(key);
		if (fluxBean == null) {
			ConcurrentHashMap<String, BlackSumSgwViewBean> newblackSumMap = new ConcurrentHashMap<String, BlackSumSgwViewBean>(blackSumMap);
			fluxBean = new BlackSumSgwViewBean();
			newblackSumMap.put(key, fluxBean);
			this.blackSumMap = newblackSumMap;
		}
		return fluxBean;
	}

	/**
	 * 周期性检查黑名单记数，进行清理
	 */
	private void checkAndRestBlackBean() {
		Map<String, BlacklistRuleView> cfgMap = SpringContext.getInstance().getConfigService().getBlackRuleCfgMap();
		
		for (String sumKey : this.blackSumMap.keySet()) {
			BlackSumSgwViewBean sumBean = this.blackSumMap.get(sumKey);
			int pos = sumKey.indexOf("[");
			if(pos < 0){
				continue;
			}
		
			String cfgKey = sumKey.substring(0, pos);
			BlacklistRuleView rule = cfgMap.get(cfgKey);
			if(rule == null){
				continue;
			}
			
			if (sumBean.getResetTime() + rule.getBlackCycle() * 1000 < System.currentTimeMillis()) {
				//sumBean.reset();
				this.blackSumMap.remove(sumKey);
			}
			
		}
	}
	
	private BlacklistRuleView getBlackCfg(CallParam callParam){
		String hostId = callParam.getUserName();
		String serviceContextId = callParam.getServiceContextId();
		String cfgKey = this.getCfgMapKey(hostId, serviceContextId);
		return SpringContext.getInstance().getConfigService().getBlackRuleCfgMap().get(cfgKey);
	}

	@Override
	public Set<String> monitorConfKeys() {
		return new HashSet<String>();
	}

	@Override
	public void onConfigUpdated(String updatedKey) {
		;
	}
	
}
